package com.nulldev.util.web.YouTubeExtractor.comments.handlers;

import static com.nulldev.util.web.YouTubeExtractor.comments.handlers.Util.__hasCreatorHeart;
import static com.nulldev.util.web.YouTubeExtractor.comments.handlers.Util.isVerified;
import static com.nulldev.util.web.YouTubeExtractor.util.YouTubeExtractorUtil.getYTString;

import java.util.List;

import com.nulldev.util.JVM.Arguments;
import com.nulldev.util.VariableAPI.MathUtil;
import com.nulldev.util.VariableAPI.StringsUtil;
import com.nulldev.util.languages.json.uniapi.UniJsonValue;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.web.YouTubeExtractor.comments.YTComment;
import com.nulldev.util.web.YouTubeExtractor.comments.YTComments;
import com.nulldev.util.web.YouTubeExtractor.comments.YTComments.YTCommentInitData;
import com.nulldev.util.web.YouTubeExtractor.comments.YTComments.YouTubeCommentResult;
import com.nulldev.util.web.YouTubeExtractor.util.YouTubeAmountFormatter;

public class ArrayCommentHandler {

	private static final Logger logger = LoggerFactory.getLoggerD(Arguments.hasArgument("--debug", "--YTComments.debug", "--trace"));

	public static YouTubeCommentResult __process_array_based_comments(final String resp, final List<YTComment> comments, final YTCommentInitData initData) {
		// TODO: We can probably nuke this.
		final UniJsonValue arr = UniJsonValue.parseArray(resp).asArray();
		final UniJsonValue mainObject = arr.get(1);
		final UniJsonValue response = mainObject.getJSONObject("response");
		if (!response.contains("continuationContents", "onResponseReceivedEndpoints")) {
			logger.error("continuationContents is missing, panicing!");
			logger.debug(resp);
			return new YouTubeCommentResult(null, comments).setCommentsDisabled(true);
		} else if (response.contains("onResponseReceivedEndpoints")) {
			UniJsonValue cc = response.get("onResponseReceivedEndpoints").last();
			if (cc == null || cc.isNull()) {
				logger.error("Failed to get comments!");
				logger.info(response);
				return new YouTubeCommentResult(null, comments);
			}
			String cont = null;
			final UniJsonValue items;
			if (cc.contains("appendContinuationItemsAction")) {
				items = cc.get("appendContinuationItemsAction").get("continuationItems");
			} else {
				items = cc.get("reloadContinuationItemsCommand").get("continuationItems");
			}
			if (items == null || items.isNull()) {
				logger.error("items is null, assuming comments are disabled!");
				if (items == null) {
					logger.warn("items became null via pointer not isNull()!");
					logger.warn(cc.toString());
				}
				return new YouTubeCommentResult(null, comments).setCommentsDisabled(true);
			}
			try {
				cont = items.last().getJSONObject("continuationItemRenderer").get("continuationEndpoint").get("continuationCommand").getString("token");
			} catch (Exception e) {
				logger.error("Failed to get continuation token!", e);
			}
			for (int i = 0; i < items.size(); i++) {
				final UniJsonValue item = items.getJsonObject(i);
				try {
					if (!item.contains("commentThreadRenderer") && !item.contains("continuationItemRenderer")) {
						logger.warn("[arr_cont] Unknown object: " + item);
						continue;
					} else if (item.contains("continuationItemRenderer")) {
						continue;
					} else {
						final UniJsonValue v = item.getJSONObject("commentThreadRenderer");
						final UniJsonValue o = v.getJSONObject("comment").getJSONObject("commentRenderer");
						final UniJsonValue r = items.getJsonObject(i).getJSONObject("commentThreadRenderer").getJSONObject("replies");
						final String authorName = o.getJSONObject("authorText").get("runs").getJsonObject(0).getString("text");
						final UniJsonValue c = o.getJSONObject("authorThumbnail").get("thumbnails");
						final String authorThumbnail = c.getJsonObject(c.size() - 1).getString("url");
						final String commentText = getYTString(o.getJSONObject("contentText"));
						final boolean isAuthorLiked = o.getBoolean("isLiked") || o.contains("creatorHeart");
						final long replyCount = o.getInt("replyCount", 0);
						final boolean hasCreatorHeart = __hasCreatorHeart(o);
						long likeCount = 0;
						if (o.contains("voteCount")) {
							final String fp = o.get("voteCount").get("runs").first().getString("text");
							if (StringsUtil.isNumber(fp)) {
								likeCount = MathUtil.safeParseL(fp, 0);
							} else
								likeCount = YouTubeAmountFormatter.format(fp);
						} else
							likeCount = o.getInt("likeCount", 0);
						String repliesCont = null;
						try {
							repliesCont = r.getJSONObject("commentRepliesRenderer").get("continuations").getJsonObject(0).getJSONObject("nextContinuationData")
									.getString("continuation");
						} catch (Exception e) {
						}
						comments.add(new YTComment(authorName, authorThumbnail, isAuthorLiked, hasCreatorHeart, o.contains("pinnedCommentBadge"), commentText,
								repliesCont, likeCount, replyCount, isVerified(o)));
					}
				} catch (Exception e) {
					logger.error("Failed to add comment!", e);
					logger.error("Object: " + item);
				}
			}
			return new YouTubeCommentResult(cont, comments);
		} else {
			UniJsonValue cc = response.getJSONObject("continuationContents").getJSONObject("commentSectionContinuation");
			if (cc == null || cc.isNull()) {
				if (response.hasValue("continuationContents")) {
					for (final UniJsonValue v : response.getJSONObject("continuationContents").get("sectionListContinuation").get("contents").asArray()) {
						if (v.hasValue("commentSectionRenderer")) {
							cc = v.get("commentSectionRenderer");
							break;
						}
					}
					String cont = null;
					try {
						cont = cc.get("continuations").get(0).getJSONObject("nextContinuationData").getString("continuation");
					} catch (Exception e) {
					}
					if (cont == null) {
						logger.error("Failed to get comments!");
						logger.info(response);
						return new YouTubeCommentResult(null, comments);
					} else {
						if (logger.debugEnabled.get()) {
							logger.error("Failed to get comments!");
							logger.info(response);
						}
						return YTComments.getComments(new YTCommentInitData(initData.getVideoID(), initData.getCookiePayload(), initData.getClientName(),
								initData.getClientVersion(), cont));
					}
				} else {
					logger.error("Failed to get comments!");
					logger.info(response);
					return new YouTubeCommentResult(null, comments);
				}
			}
			String cont = null;
			try {
				cont = cc.get("continuations").get(0).getJSONObject("nextContinuationData").getString("continuation");
			} catch (Exception e) {
			}
			final UniJsonValue items = cc.get("items");
			if (items == null || items.isNull()) {
				logger.error("items is null, assuming comments are disabled!");
				if (items == null) {
					logger.warn("items became null via pointer not isNull()!");
					logger.warn(cc.toString());
				}
				return new YouTubeCommentResult(null, comments).setCommentsDisabled(true);
			}
			for (int i = 0; i < items.size(); i++) {
				try {
					final UniJsonValue o = items.getJsonObject(i).getJSONObject("commentThreadRenderer").getJSONObject("comment")
							.getJSONObject("commentRenderer");
					final UniJsonValue r = items.getJsonObject(i).getJSONObject("commentThreadRenderer").getJSONObject("replies");
					final String authorName = o.getJSONObject("authorText").get("runs").getJsonObject(0).getString("text");
					final UniJsonValue c = o.getJSONObject("authorThumbnail").get("thumbnails");
					final String authorThumbnail = c.getJsonObject(c.size() - 1).getString("url");
					final String commentText = getYTString(o.getJSONObject("contentText"));
					final boolean isAuthorLiked = o.getBoolean("isLiked") || o.contains("creatorHeart");
					final long replyCount = o.getInt("replyCount", 0);
					final boolean hasCreatorHeart = __hasCreatorHeart(o);
					long likeCount = 0;
					if (o.contains("voteCount")) {
						final String fp = o.get("voteCount").get("runs").first().getString("text");
						if (StringsUtil.isNumber(fp)) {
							likeCount = MathUtil.safeParseL(fp, 0);
						} else
							likeCount = YouTubeAmountFormatter.format(fp);
					} else
						likeCount = o.getInt("likeCount", 0);
					String repliesCont = null;
					try {
						final UniJsonValue commentRepliesRenderer = r.getJSONObject("commentRepliesRenderer");
						if (commentRepliesRenderer.contains("continuations")) {
							repliesCont = commentRepliesRenderer.get("continuations").getJsonObject(0).getJSONObject("nextContinuationData")
									.getString("continuation");
						} else {
							repliesCont = commentRepliesRenderer.get("contents").getJsonObject(0).getJSONObject("continuationItemRenderer")
									.getJSONObject("continuationEndpoint").getJSONObject("continuationCommand").getString("token");
						}
					} catch (Exception e) {
					}
					comments.add(new YTComment(authorName, authorThumbnail, isAuthorLiked, hasCreatorHeart, o.contains("pinnedCommentBadge"), commentText,
							repliesCont, likeCount, replyCount, isVerified(o)));
				} catch (Exception e) {
					logger.error("Failed to add comment!", e);
				}
			}
			return new YouTubeCommentResult(cont, comments);
		}
	}
}
